
/**
  ******************************************************************************
  * Copyright 2021 The Microbee Authors. All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  * 
  * http://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * 
  * @file       gp_iomcu.h
  * @author     baiyang
  * @date       2021-12-26
  ******************************************************************************
  */

#pragma once

#ifdef __cplusplus
extern "C"{
#endif

/*----------------------------------include-----------------------------------*/
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>

#include <stdint.h>
#include <stdbool.h>

#include "iofirmware/ioprotocol.h"

#include <board_config/borad_config.h>
/*-----------------------------------macro------------------------------------*/

/*----------------------------------typedef-----------------------------------*/
#if defined(HAL_WITH_IO_MCU)

typedef rt_uint32_t        eventmask_t;    /**< Mask of event identifiers. */

enum {
    PROTO_NOP               = 0x00,
    PROTO_OK                = 0x10,
    PROTO_FAILED            = 0x11,
    PROTO_INSYNC            = 0x12,
    PROTO_INVALID           = 0x13,
    PROTO_BAD_SILICON_REV   = 0x14,
    PROTO_EOC               = 0x20,
    PROTO_GET_SYNC          = 0x21,
    PROTO_GET_DEVICE        = 0x22,
    PROTO_CHIP_ERASE        = 0x23,
    PROTO_CHIP_VERIFY       = 0x24,
    PROTO_PROG_MULTI        = 0x27,
    PROTO_READ_MULTI        = 0x28,
    PROTO_GET_CRC           = 0x29,
    PROTO_GET_OTP           = 0x2a,
    PROTO_GET_SN            = 0x2b,
    PROTO_GET_CHIP          = 0x2c,
    PROTO_SET_DELAY         = 0x2d,
    PROTO_GET_CHIP_DES      = 0x2e,
    PROTO_REBOOT            = 0x30,

    INFO_BL_REV       = 1,        /**< bootloader protocol revision */
    BL_REV            = 5,        /**< supported bootloader protocol  */
    INFO_BOARD_ID     = 2,        /**< board type */
    INFO_BOARD_REV    = 3,        /**< board revision */
    INFO_FLASH_SIZE   = 4,        /**< max firmware size in bytes */

    PROG_MULTI_MAX    = 248,      /**< protocol max is 255, must be multiple of 4 */
};

/** @ 
  * @brief  
  */
typedef struct {
    // IOMCU thread
    rt_thread_t thread_ctx;

    struct rt_timer io_timer;
    struct rt_event io_event;

    rt_device_t puart;              // 对应串口
    rt_sem_t    tx_sem;             // 用于DMA模式下触发回调的信号量
    rt_size_t   rx_buff_length;     // 串口接收缓冲区数据长度

    uint32_t initial_event_mask;

    // time when we last read various pages
    uint32_t last_status_read_ms;
    uint32_t last_rc_read_ms;
    uint32_t last_servo_read_ms;
    uint32_t last_safety_option_check_ms;

    // last value of safety options
    uint16_t last_safety_options;

    // have we forced the safety off?
    bool safety_forced_off;

    // was safety off on last status?
    bool last_safety_off;

    // CONFIG page
    struct page_config config;

    // PAGE_STATUS values
    struct page_reg_status reg_status;
    uint32_t last_log_ms;

    // PAGE_RAW_RCIN values
    struct page_rc_input rc_input;
    uint32_t rc_last_input_ms;

    // MIXER values
    struct page_mixing mixing;

    // output pwm values
    struct {
        uint8_t num_channels;
        uint16_t pwm[IOMCU_MAX_CHANNELS];
        uint16_t safety_mask;
        uint16_t failsafe_pwm[IOMCU_MAX_CHANNELS];
        uint8_t failsafe_pwm_set;
        uint8_t failsafe_pwm_sent;
    } pwm_out;

    // read back pwm values
    struct {
        uint16_t pwm[IOMCU_MAX_CHANNELS];
    } pwm_in;

    // output rates
    struct {
        uint16_t freq;
        uint16_t chmask;
        uint16_t default_freq;
        uint16_t sbus_rate_hz;
        bool oneshot_enabled;
        bool brushed_enabled;
    } rate;

    struct page_GPIO GPIO;

    // IMU heater duty cycle
    uint8_t heater_duty_cycle;

    uint64_t last_servo_out_us;

    bool corked;
    bool do_shutdown;
    bool done_shutdown;

    bool crc_is_ok;
    bool detected_io_reset;
    bool initialised;
    bool is_chibios_backend;

    uint32_t protocol_fail_count;
    uint32_t protocol_count;
    uint32_t total_errors;
    uint32_t num_delayed;
    uint32_t last_iocmu_timestamp_ms;
    uint32_t read_status_errors;
    uint32_t read_status_ok;
    uint32_t last_rc_protocols;

    // firmware upload
    const uint8_t *fw;
    uint32_t fw_size;
} iomcu;

/*----------------------------------variable----------------------------------*/

/*-------------------------------------os-------------------------------------*/

/*----------------------------------function----------------------------------*/
void iomcu_ctor();
bool iomcu_init(void);

void iomcu_write_channel(uint8_t chan, uint16_t pwm);
enum safety_state iomcu_get_safety_switch_state(void);

// force safety on/off
bool iomcu_force_safety_on(void);
void iomcu_force_safety_off(void);

// read from one channel
uint16_t iomcu_read_channel(uint8_t chan);

// cork output
void iomcu_cork(void);

// push output
void iomcu_push(void);

// set output frequency
void iomcu_set_freq(uint16_t chmask, uint16_t freq);

// get output frequency
uint16_t iomcu_get_freq(uint16_t chan);

// enable SBUS out
bool iomcu_enable_sbus_out(uint16_t rate_hz);

/*
  check for new RC input
*/
bool iomcu_check_rcinput(uint64_t *last_frame_us, uint8_t *num_channels, uint16_t *channels, uint8_t max_chan);

// set IMU heater target
void iomcu_set_heater_duty_cycle(uint8_t duty_cycle);

// set default output rate
void iomcu_set_default_rate(uint16_t rate_hz);

// setup for oneshot mode
void iomcu_set_oneshot_mode(void);

// setup for brushed mode
void iomcu_set_brushed_mode(void);

/*
  set the pwm to use when in FMU failsafe
 */
void iomcu_set_failsafe_pwm(uint16_t chmask, uint16_t period_us);

// set mask of channels that ignore safety state
void iomcu_set_safety_mask(uint16_t chmask);

/*
  check that IO is healthy. This should be used in arming checks
 */
bool iomcu_healthy(void);

/*
  shutdown protocol, ready for reboot
 */
void iomcu_shutdown(void);

/*
  request bind on a DSM radio
 */
void iomcu_bind_dsm(uint8_t mode);

/*
  return the RC protocol name
 */
const char *iomcu_get_rc_protocol(void);

// get receiver RSSI
int16_t iomcu_get_RSSI(void);

// Check if pin number is valid for GPIO
bool iomcu_valid_GPIO_pin(uint8_t pin);

// convert external pin numbers 101 to 108 to internal 0 to 7
bool iomcu_convert_pin_number(uint8_t* pin);

// set GPIO mask of channels setup for output
void iomcu_set_GPIO_mask(uint8_t mask);

// write to a output pin
void iomcu_write_GPIO(uint8_t pin, bool value);

// toggle a output pin
void iomcu_toggle_GPIO(uint8_t pin);

uint8_t iomcu_get_ch_masks_size();
const uint8_t* iomcu_ch_masks();

/*
  get servo rail voltage adc counts
 */
uint16_t iomcu_get_vservo_adc_count(void);

/*
  get rssi voltage adc counts
 */
uint16_t iomcu_get_vrssi_adc_count(void);
/*------------------------------------test------------------------------------*/

#endif

#ifdef __cplusplus
}
#endif



